/**
 * @file smt.c
 * @author mjsz (1349513606@qq.com)
 * @brief 步进电机驱动模块
 * @version 0.1
 * @date 2025-05-23
 *
 * @copyright Copyright (c) 2025
 *
 */

#include "smt.h"
#include "math.h"
#include "gpio_pin.h"
__USED static inline uint8_t __smt_is_inorigin(smt_t obj)
{
    return pin_get(obj->hw->limit_pin) == obj->hw->limit_lvl ? 1 : 0;
}

static void __smt_start_motion(smt_t obj)
{
    pin_set(obj->hw->step_pin, 0);                                                            // 关闭步进脉冲
    obj->curve_state = SMT_STATE_ACCELERATE;                                                  // 设置运动状态为加速
    __HAL_TIM_SET_COUNTER(obj->hw->htim, 0);                                                  // 重置定时器计数器
    __HAL_TIM_SET_PRESCALER(obj->hw->htim, obj->vel_curve.acc_tab[obj->vel_curve.acc_steps]); // 设置定时器预分频为加速阶段的初始频率

    __HAL_TIM_ENABLE_IT(obj->hw->htim, TIM_IT_UPDATE | obj->hw->pwm_chx_itr); // 使能定时器更新和PWM中断
    __HAL_TIM_ENABLE(obj->hw->htim);                                          // 启动定时器PWM输出
}

int smt_back_origin(smt_t obj, smt_evt_cb evt_handler)
{
    if (obj == NULL) // 检查对象和定时器句柄是否有效
    {
        return err_invalid_obj; // 返回错误
    }
    obj->dir = SMT_DIR_BACKWARD;  // 设置为反转
    obj->op_type = SMT_OP_ORIGIN; // 设置操作类型为回原点
    if (evt_handler != NULL)
    {
        obj->evt_handler = evt_handler; // 设置事件回调函数
    }
    stm_vel_curve_cacl(obj->origin_vel_params, &obj->vel_curve, obj->mech_params.max_steps); // 计算速度曲线
    __smt_start_motion(obj);                                                                 // 启动运动
    return 0;
}

int smt_abs_move(smt_t obj, int target_pos, smt_evt_cb evt_handler)
{
    if (obj == NULL) // 检查对象和定时器句柄是否有效
    {
        return err_invalid_obj; // 返回错误
    }

    if (target_pos > obj->mech_params.max_steps) // 检查目标位置是否超过最大步数
    {
        return err_invalid_param; // 返回错误
    }

    if (target_pos == obj->cur_pos) // 如果目标位置和当前位置相同
    {
        return err_ok; // 返回成功
    }

    if (target_pos < obj->cur_pos) // 如果目标位置小于当前位置
    {
        obj->dir = SMT_DIR_BACKWARD; // 设置为反转
    }
    else
    {
        obj->dir = SMT_DIR_FORWARD; // 设置为正转
    }
    obj->op_type = SMT_OP_MOVE; // 设置操作类型为移动
    if (evt_handler != NULL)
    {
        obj->evt_handler = evt_handler; // 设置事件回调函数
    }
    stm_vel_curve_cacl(obj->target_vel_params, &obj->vel_curve, abs(target_pos - obj->cur_pos)); // 计算速度曲线
    __smt_start_motion(obj);                                                                     // 启动运动
    return 0;
}

int smt_rel_move(smt_t obj, int target_pos, smt_evt_cb evt_handler) // 相对移动
{
    if (obj == NULL) // 检查对象是否有效
    {
        return err_invalid_obj;
    }

    int abs_target = obj->cur_pos + target_pos;
    return smt_abs_move(obj, abs_target, evt_handler);
}

int smt_stop(smt_t obj)
{
    if (obj == NULL)
    {
        return err_invalid_obj;
    }

    // 关闭定时器中断
    __HAL_TIM_DISABLE_IT(obj->hw->htim, TIM_IT_UPDATE | obj->hw->pwm_chx_itr);
    // 停止定时器PWM输出
    __HAL_TIM_DISABLE(obj->hw->htim);

    // 设置状态为停止
    obj->curve_state = SMT_STATE_STOPPED;

    return err_ok;
}